package com.rainwen.shiro.realm;

import com.rainwen.shiro.entity.User;
import com.rainwen.shiro.enums.UserStatus;
import com.rainwen.shiro.service.MyCredentialsMatcher;
import com.rainwen.shiro.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.ArrayList;
import java.util.List;

/**
 * 用户认证器
 * http://blog.csdn.net/ccdust/article/details/52300287
 *
 * Created by rain.wen on 2017/8/9.
 */
public class UserRealm extends AuthorizingRealm {

    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String)principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(userService.findRoles(username)); //读取数据库角色
        authorizationInfo.setStringPermissions(userService.findPermissions(username)); //读取用户权限

        return authorizationInfo;
    }

    /**
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String)token.getPrincipal();
        User user = userService.findByUsername(username);
        if(user == null) {
            throw new UnknownAccountException();//没找到帐号
        }
        if(UserStatus.LOCKED.getKey() == user.getStatus()) {
            throw new LockedAccountException(); //帐号锁定
        }
        List<Object> principals = new ArrayList<Object>(2);
        principals.add(user.getUsername());
        principals.add(user);

        //实际在此处主要是进行密码匹配
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                principals, //密码验证通过此对象会放入作用域
                user.getPassword(), //密码
                ByteSource.Util.bytes(user.getSalt()),//salt
                getName()  //realm name
        );
        return authenticationInfo;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}
